package middleware

import (
	"app/wd"
	"bytes"
	"encoding/json"
	"time"

	"github.com/gin-gonic/gin"
)

// Response ...
type Response struct {
	Type         string `json:"type"`
	Method       string `json:"method"`
	Path         string `json:"path"`
	Code         int    `json:"code"`
	Duration     string `json:"duration"`
	ResponseBody string `json:"response_body"`
}

// Request ...
type Request struct {
	Type     string `json:"type"`
	Method   string `json:"method"`
	Path     string `json:"path"`
	Query    string `json:"query"`
	Code     int    `json:"code"`
	PostRaw  string `json:"post_raw"`
	ClientID string `json:"client_id"`
}
type ResponseWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

//重写 Write([]byte) (int, error) 方法
func (w ResponseWriter) Write(b []byte) (int, error) {
	//向一个bytes.buffer中写一份数据来为获取body使用
	w.body.Write(b)
	//完成gin.Context.Writer.Write()原有功能
	return w.ResponseWriter.Write(b)
}

// LogMiddleware 日志中间件
func LogMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Set("trace_id", wd.GetTraceID())
		method := c.Request.Method
		statusCode := c.Writer.Status()
		start := time.Now()
		path := c.Request.URL.Path
		postRaw := c.Request.PostForm.Encode()
		responseWriter := ResponseWriter{
			ResponseWriter: c.Writer,
			body:           bytes.NewBuffer([]byte{}),
		}
		c.Writer = responseWriter
		// 请求日志
		logStr, _ := json.Marshal(Request{
			Type:     "request",
			Method:   c.Request.Method,
			Path:     path,
			Query:    c.Request.URL.RawQuery,
			Code:     statusCode,
			PostRaw:  postRaw,
			ClientID: c.ClientIP(),
		})
		wd.App.SysLog.WithContext(c).WithField("type", "sys").Infof(string(logStr))
		c.Next()
		end := time.Now()
		timeSub := end.Sub(start)

		// 响应日志
		responseBodyStr := responseWriter.body.String()
		logStr, _ = json.Marshal(Response{
			Type:         "response",
			Method:       method,
			Path:         path,
			Code:         statusCode,
			Duration:     timeSub.String(),
			ResponseBody: responseBodyStr,
		})
		wd.App.SysLog.WithContext(c).WithField("type", "sys").Infof(string(logStr))
	}
}
